﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

using Microsoft.Win32;

namespace Mine
{
    enum ThreadingType { SingleThread = 0, ThreadPool = 1,ThreadPoolSort=2, MultiThread = 3, Last=4 }
    enum SecurityTpe { None = 0, Locked = 1, InterlockedOperations = 2, InterlockedLockActive = 3, InterlockedLockSleep = 4,Last=5 }
    class Tester
    {
        private void Test(int StationNumber, int MoveNumber, int StartStone, int StoneAmount, SecurityTpe st, ThreadingType tt, MineType mt, System.IO.TextWriter tw)
        {
            tw.WriteLine("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
            tw.WriteLine(string.Format("{0} stations", StationNumber));
            tw.WriteLine(string.Format("{0} stone at the start", StartStone));
            tw.WriteLine(string.Format("{0} stones per move", StoneAmount));
            tw.WriteLine(string.Format("{0} moves", MoveNumber));
            tw.WriteLine(string.Format("{0} threading type", tt));
            tw.WriteLine(string.Format("{0} mine type", mt));
            tw.WriteLine(string.Format("{0} security type", st));
            tw.WriteLine("--------------------------------------------------------------");
            IMine Mine;
            switch (st)
            {
                case SecurityTpe.None:
                    Mine = new Mine<SimpleStation>();
                    Mine.BuildMine(StoneAmount, StartStone, StationNumber, mt);
                    break;
                case SecurityTpe.Locked:
                    Mine = new Mine<LockedStation>();
                    Mine.BuildMine(StoneAmount, StartStone, StationNumber, mt);
                    break;
                case SecurityTpe.InterlockedOperations:
                    Mine = new Mine<InterlockedStation>();
                    Mine.BuildMine(StoneAmount, StartStone, StationNumber, mt);
                    break;
                case SecurityTpe.InterlockedLockActive:
                    Mine = new Mine<InterlockedLockingStationActive>();
                    Mine.BuildMine(StoneAmount, StartStone, StationNumber, mt);
                    break;
                case SecurityTpe.InterlockedLockSleep:
                    Mine = new Mine<InterlockedLockingStationSleep>();
                    Mine.BuildMine(StoneAmount, StartStone, StationNumber, mt);
                    break;
                default: throw new Exception("incorrect enum");
            }
            List<Simulator> SL = Mine.Simulation;
            Track.IsFinished.Reset();
            DateTime start = DateTime.Now;
            switch (tt)
            {
                case ThreadingType.SingleThread:

                    foreach (Simulator s in SL)
                    {
                        s(MoveNumber);
                    }
                    break;
                case ThreadingType.ThreadPool: //threadpoollal: betoljuk az összeset a queueba

                    //ThreadPool.SetMaxThreads(5, 1);
                    foreach (Simulator s in SL)
                    {
                        ThreadPool.QueueUserWorkItem(new WaitCallback(s), MoveNumber);
                    }
                    break;
                case ThreadingType.ThreadPoolSort: //threadpoollal: betoljuk az összeset a queueba

                    ThreadPool.SetMaxThreads(5, 1);
                    for (int i = 0; i * 2 < SL.Count; i++)
                    {
                        ThreadPool.QueueUserWorkItem(new WaitCallback(SL[i * 2]), MoveNumber);
                    }
                    for (int i = 0; i * 2+1 < SL.Count; i++)
                    {
                        ThreadPool.QueueUserWorkItem(new WaitCallback(SL[i * 2+1]), MoveNumber);
                    }
                    break;
                case ThreadingType.MultiThread: //threadpoollal: betoljuk az összeset a queueba
                    List<Thread> A = new List<Thread>();
                    foreach (Simulator s in SL)
                    {
                        A.Add(new Thread(new ParameterizedThreadStart(s)));
                    }
                    foreach (Thread a in A)
                    {
                        a.Start(MoveNumber);
                    }
                    break;
                default: throw new Exception("incorrect enum");
            }
            Track.IsFinished.WaitOne();//várjuk a végét
            DateTime finish = DateTime.Now;
            Mine.Print(tw);
            tw.WriteLine("--------------------------------------------------------------");
            tw.WriteLine("started at: {0}", start.ToString());
            tw.WriteLine("finished at: {0}", finish.ToString());
            tw.WriteLine(String.Format(System.Globalization.CultureInfo.InvariantCulture, "total time: {0:000000.000}ms", (finish - start).TotalMilliseconds));
            tw.WriteLine("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

        }

        public void TestAll(System.IO.TextWriter tw, string s)
        {
            tw.WriteLine(s);
            System.IO.StringWriter sw = new System.IO.StringWriter(new StringBuilder());//JIT

            for (int st = 0; st < (int)SecurityTpe.Last; st++)
            {
                for (int tt = 0; tt < (int)ThreadingType.Last; tt++)
                {
                    for (int mt = 0; mt < (int)MineType.Last ; mt++)
                    {
                        Console.WriteLine("{0}{1}{2}", st, tt, mt);
                        Test(2, 3, 100, 1, (SecurityTpe)st, (ThreadingType)tt, (MineType)mt, sw);//JIT ezt nem irjuk ki

                        Test(5, 5000000, 10000000, 1, (SecurityTpe)st, (ThreadingType)tt, (MineType)mt, tw);
                        if (mt != (int)MineType.Complete)
                        {
                            Test(5, 5000000, 10000000, 5, (SecurityTpe)st, (ThreadingType)tt, (MineType)mt, tw);
                            Test(20, 300000, 10000000, 10, (SecurityTpe)st, (ThreadingType)tt, (MineType)mt, tw);
                        }
                        if (mt != (int)MineType.Complete && mt != (int)ThreadingType.MultiThread)
                        {
                            Test(2000, 30000, 10000000, 10, (SecurityTpe)st, (ThreadingType)tt, (MineType)mt, tw);
                            Test(100, 200000, 100000000, 5, (SecurityTpe)st, (ThreadingType)tt, (MineType)mt, tw);
                        }
                    }
                }
            }
            Console.WriteLine("FINISHED");
        }
    }
}